package org.jetlinks.community.device.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.jetlinks.community.device.entity.PlayBackStreamParam;
import org.jetlinks.community.device.entity.PresetView;
import org.jetlinks.community.device.entity.VideoScreen;
import org.jetlinks.community.device.entity.LiveStreamParam;
import org.jetlinks.community.device.enums.ActionEnum;
import org.jetlinks.community.device.enums.CommandHiKEnum;
import org.jetlinks.community.device.service.VideoPlayService;
import org.jetlinks.community.device.service.hik.HiKClient;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;

@Service
@Slf4j
public class VideoPlayServiceImpl implements VideoPlayService {

    @Resource
    private HiKClient hiKClient;

    @Override
    public Mono<VideoScreen> getLiveStream(LiveStreamParam liveStreamParam) {
        Mono<List<PresetView>> presets = getPresets(liveStreamParam.getCameraIndexCode());
        String liveStream = hiKClient.getLiveStream(liveStreamParam);

        return Mono.just(liveStream)
            .transform(adapt)
            .map(jsonObject -> jsonObject.getJSONObject("data").getString("url"))

            .zipWith(presets, (url, preset) ->
                VideoScreen
                    .builder()
                    .id(liveStreamParam.getCameraIndexCode())
                    .presets(preset)
                    .url(url)
                    .build()
            );
    }

    @Override
    public Mono<VideoScreen> getPlayBackStream(PlayBackStreamParam playBackStreamParam) {

        return Mono.just(hiKClient.getBackStream(playBackStreamParam))
            .transform(adapt)
            .map(jsonObject -> {
                String url = jsonObject.getJSONObject("data").getString("url");
                return VideoScreen
                    .builder()
                    .url(url)
                    .id(playBackStreamParam.getCameraIndexCode())
                    .build();
            });
    }

    @Override
    public Mono<Void> ptz(String moId, CommandHiKEnum direction) {
        Mono<Void> start = Mono
            .just(hiKClient.ptzControl(moId, direction, ActionEnum.start, null))
            .transform(adapt)
            .then();

        Mono<Void> stop = Mono
            .fromCallable(() -> {
                Thread.sleep(2000);
                return hiKClient.ptzControl(moId, direction, ActionEnum.stop, null);
            })
            .publishOn(Schedulers.elastic())
            .transform(adapt)
            .then();
        return start.concatWith(stop).then();
    }

    @Override
    public Mono<List<PresetView>> getPresets(String moId) {
        return Mono.just(hiKClient.presetList(moId))
            .transform(adapt)
            .map(response -> {
                JSONObject data = response.getJSONObject("data");
                JSONArray list = data.getJSONArray("list");
                return JSON.parseArray(list.toJSONString(), PresetView.class);
            }).publishOn(Schedulers.elastic());
    }

    @Override
    public Mono<PresetView> addPreset(PresetView presetView) {
        String moId = presetView.getCameraIndexCode();
        String name = presetView.getPresetPointName();
        Integer preset = presetView.getPresetPointIndex();

        return Mono
            .just(hiKClient.addPresets(moId, name, preset))
            .transform(adapt)
            .map(response -> PresetView.builder().cameraIndexCode(moId).presetPointIndex(preset).presetPointName(name).build())
            .publishOn(Schedulers.elastic());
    }

    @Override
    public Mono<Void> invokePreset(String moId, Integer preset) {
        return Mono
            .just(hiKClient.ptzControl(moId, CommandHiKEnum.GOTO_PRESET, ActionEnum.start, preset))
            .transform(adapt)
            .then()
            .publishOn(Schedulers.elastic());
    }

    @Override
    public Mono<Integer> deletePreset(String moId, Integer preset) {
        return Mono
            .just(hiKClient.deletePreset(moId, preset))
            .transform(adapt)
            .map(jsonObject -> preset)
            .publishOn(Schedulers.elastic());
    }

    @Override
    public Mono<Void> videoScreen(String projectId, Integer page, Integer pageSize) {
        return null;
    }

    // 转化海康威视的数据格式
    Function<Mono<String>, Mono<JSONObject>> adapt = response -> response.map(r -> {
        JSONObject jsonObject = JSON.parseObject(r);
        String code = jsonObject.getString("code");
        if (!Objects.equals(code, "0")) {
            throw new RuntimeException(r);
        }
        return jsonObject;
    });

}
